package facade

import "sync"

var (
	facadeApi FacadeApi
	once      sync.Once
)

type FacadeApi interface {
	// Test 这是对外提供的组合方法
	Test() string
	// TestA TestB TestC这些是A、B、C模块对子系统外的接口，这样外部就不需要知道A、B、C模块的存在
	// 只需要知道Facade接口就行了
	TestA() string
	TestB() string
	TestC() string
}

// AModuleApi A模块的接口
type AModuleApi interface {
	// TestA 示意方法，A模块对外的一个功能方法
	TestA() string
	// 子系统内部使用的方法...
}

// BModuleApi B模块的接口
type BModuleApi interface {
	// TestB 示意方法，B模块对外的一个功能方法
	TestB() string
	// 子系统内部使用的方法...
}

// CModuleApi C模块的接口
type CModuleApi interface {
	// TestC 示意方法，C模块对外的一个功能方法
	TestC() string
	// 子系统内部使用的方法...
}

type Facade struct {
	a AModuleApi
	b BModuleApi
	c CModuleApi
}

func (f *Facade) TestA() string {
	return f.a.TestA()
}

func (f *Facade) TestB() string {
	return f.b.TestB()
}

func (f *Facade) TestC() string {
	return f.c.TestC()
}

// NewFacade 创建单例外观类
func NewFacade() FacadeApi {
	once.Do(func() {
		facadeApi = &Facade{
			a: NewAModuleApi(),
			b: NewBModuleApi(),
			c: NewCModuleApi(),
		}
	})
	return facadeApi
}

// Test 示意方法，满足客户需要的功能
func (f *Facade) Test() string {
	// 在内部实现的时候，可能会调用到内部的多个模块
	return f.a.TestA() + f.b.TestB() + f.c.TestC()
}

type AModule struct {
}

func NewAModuleApi() AModuleApi {
	return &AModule{}
}

func (a *AModule) TestA() string {
	return "AModel TestA"
}

type BModule struct {
}

func NewBModuleApi() BModuleApi {
	return &BModule{}
}

func (b *BModule) TestB() string {
	return "BModel TestB"
}

type CModule struct {
}

func NewCModuleApi() CModuleApi {
	return &CModule{}
}

func (c *CModule) TestC() string {
	return "CModel TestC"
}
